var goManifest, goOptionsStructure, goOptions;

function debugLog(sMessage) {
  if (goOptions === undefined || goOptions.debug === undefined || goOptions.debug.output === undefined ||
      !goOptions.debug.output) return;
  var sCaller = new String(arguments.callee.caller).replace(/^function\s+|\([\s\S]+$/g, "");
  if (goManifest) sCaller = goManifest.name + "::" + sCaller;
  console.log(sCaller + ":\r\n" + sMessage);
}

function repr(uValue) {
  if (uValue === undefined || uValue === null || uValue.constructor == Number || uValue.constructor == Boolean) {
    return new String(uValue);
  } else if (uValue.constructor == Array) {
    var aValues = [];
    for (var i = 0; i < uValue.length; i++) {
      aValues.push(i + ":" + repr(uValue[i]));
    }
    return "[" + aValues.join(", ") + "]";
  } else if (uValue.constructor == Object) {
    var aValues = [];
    for (sMemberName in uValue) {
      aValues.push(repr(sMemberName) + ":" + repr(uValue[sMemberName]));
    }
    return "{" + aValues.join(", ") + "}";
  } else {
    // TODO: Add handling of other types.
    sString = new String(uValue);
    return "\"" + sString.replace(/[\r\n\"]/g, function (sMatch) {
      if (sMatch == "\r") return "\\r";
      if (sMatch == "\n") return "\\n";
      if (sMatch == "\"") return "\\\"";
    }) + "\"";
  }
}

function assert(bCheck, sMessage) {
  if (!bCheck) assertionError(sMessage);
}
function assertionError(sMessage) {
  throw new Error("AssertionError: " + sMessage);
}
